package themidibus;

import static javax.sound.midi.ShortMessage.ACTIVE_SENSING;
import static javax.sound.midi.ShortMessage.CHANNEL_PRESSURE;
import static javax.sound.midi.ShortMessage.CONTROL_CHANGE;
import static javax.sound.midi.ShortMessage.NOTE_OFF;
import static javax.sound.midi.ShortMessage.NOTE_ON;
import static javax.sound.midi.ShortMessage.PITCH_BEND;
import static javax.sound.midi.ShortMessage.POLY_PRESSURE;
import static javax.sound.midi.ShortMessage.PROGRAM_CHANGE;
import static javax.sound.midi.ShortMessage.SYSTEM_RESET;

import javax.sound.midi.MidiChannel;

import org.tritonus.share.midi.MidiUtils;

import themidibus.listener.ChannelBasedMidiListener;
import themidibus.listener.SimpleMidiListener;

abstract class MidiMessageDecoder {

	static final void deliverSimpleMidiEvent(SimpleMidiListener listener, byte[] data, long timeStamp) {
		int data_0, data_1;
		data_0 = data[0] & 0xF0;
		data_1 = data[0] & 0x0F;
		float val;
		switch (data_0) {
		case ACTIVE_SENSING:
			listener.activeSensing(timeStamp);
			break;
		case NOTE_ON:
			listener.noteOn(data_1, data[1], data[2]);
			break;
		case NOTE_OFF:
			listener.noteOff(data_1, data[1], data[2]);
			break;
		case PITCH_BEND:
			if (data[1] == 64 && data[2] == 64) {
				val = 0;
			} else {
				val = MidiUtils.get14bitValue(data[1], data[2]) * 4f / Short.MAX_VALUE - 1;
			}
			listener.pitchBend(data_1, val);
			break;
		case CONTROL_CHANGE:
			switch (data[1]) {
			case 0:
				listener.sustainChange(data[1] > 0);
				break;
			case 7:
				val = data[2] / 128f;
				listener.channelVolume(data_1, val);
				break;
			default:
				listener.controllerChange(data_1, data[1], data[2]);
			}
			break;
		case PROGRAM_CHANGE:
			listener.programChange(data_1, data[1]);
			break;
		case POLY_PRESSURE:
			break;
		case CHANNEL_PRESSURE:
			val = data[1] / 128f;
			listener.channelPressure(data_1, val);
			break;
		case SYSTEM_RESET:
			// listener.systemReset();
			break;
		}
	}

	static final void deliverChannelBasedMidiEvent(ChannelBasedMidiListener listener, byte[] data, long timeStamp) {
		int channel_num = data[0] & 0x0F;
		int command = data[0] & 0xF0;
		MidiChannel channel = listener.getChannel(channel_num);
		switch (command) {
		case ACTIVE_SENSING:
			break;
		case NOTE_ON:
			channel.noteOn(data[1], data[2]);
			break;
		case NOTE_OFF:
			channel.noteOff(data[1], data[2]);
			break;
		case PITCH_BEND:
			channel.setPitchBend(MidiUtils.get14bitValue(data[1], data[2]));
			break;
		case CONTROL_CHANGE:
			channel.controlChange(data[1], data[2]);
			break;
		case PROGRAM_CHANGE:
			channel.programChange(data[1]);
			break;
		case POLY_PRESSURE:
			channel.setPolyPressure(data[1], data[2]);
			break;
		case CHANNEL_PRESSURE:
			channel.setChannelPressure(data[1]);
			break;
		case SYSTEM_RESET:
			channel.resetAllControllers();
			break;
		}
	}

}
